﻿using System.Windows;
using System.Windows.Controls;
using Gwn.Library.MvpVm.Events;
using Gwn.Library.MvpVm.Extensions;
using Gwn.Library.MvpVm.Interfaces;
using Gwn.Library.MvpVm.Types;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Unity;

namespace Gwn.Library.MvpVm.Base
{
    /// <summary>
    /// 
    /// </summary>
    public class PresenterBase : ClassBase, IPresenter
    {
        private IView _view;
        private IViewModel _viewModel;

        /// <summary>
        /// Gets or sets the view.
        /// </summary>
        /// <value>The view.</value>
        public IView View
        {
            get { return _view; }
            set
            {
                Logger.LogDebug("View SET (" + value.GetType() + ")", GetType());
                _view = value;
            }
        }

        /// <summary>
        /// Gets or sets the is active presenter.
        /// </summary>
        /// <value>The is active presenter.</value>
        public bool IsActivePresenter { get; set; }

        /// <summary>
        /// Gets or sets the view model.
        /// </summary>
        /// <value>The view model.</value>
        public IViewModel ViewModel
        {
            get { return _viewModel; }
            set
            {
                Logger.LogDebug("ViewModel SET (" + value.GetType() + ")", GetType());
                _viewModel = value;
            }
        }

        /// <summary>
        /// Called by ContainerPropertySet() when Container is set by Unity container
        /// </summary>
        /// <value>The start date.</value>
        public virtual void Initialize()
        {
            Logger.LogDebug("Initialize", GetType());

            // Instantiate View and ViewModel
            View = Container.Resolve<IView>();
            ViewModel = Container.Resolve<IViewModel>();

            // If the view model implements IViewModelCommand then wireup
            // the command 
            if (ViewModel is IViewModelCommand)
                ((IViewModelCommand) ViewModel).Command = 
                    new DelegateCommand<object>(HandleCommandExecuteMethod, HandleCommandCanExecuteMethod);

            // Initialize the View (loads merged resource dictionary)
            // if not overridden
            View.Initialize();

            // Gwn.Library.Resources.DataTemplates.xaml holds the
            // DataTemplate for the ViewModels.  Since the Phone
            // and Silverlight do not support DataType we had to go with
            // a control that would support DataTemplates on all three 
            // platforms.  The ViewModelHolder is an ItemsControl so we
            // have to add the ViewModel to it; it is available via
            // DataContext as well as in ItemsControl (for template).
            // [More]http://www.global-webnet.net/blogengine/post/2011/09/02/Window-Phone-and-Silverlight-emulating-DataType.aspx
            if (View is IViewModelHolder)
            {
                var itemsControl = ((IViewModelHolder)View).ViewModel;

                // Since our ViewModel reference is placed in the ItemsControl
                // we can simply update it without having to manage the ItemsControl
                itemsControl.Items.Add(ViewModel);

                // Get the default data template name for the view mode
                var templateName = ViewModel.GetType().Name + "Template";

                // If there is a data template defined then assign it to the
                // items control
                var dataTemplate = ((UserControl)View).Resources[templateName] as DataTemplate;
                if (dataTemplate != null)
                    itemsControl.ItemTemplate = dataTemplate;
            }

            // Configure data context to use specified view model. 
            View.DataContext = ViewModel;

            // Publish event that we have a new view
            EventAggregator.GetEvent<ProcessEvent>()
                .Publish(new ProcessEventArgs
                {
                    Data = this,
                    ProcessType = ProcessType.NewView
                });
        }

        /// <summary>
        /// Handles the execute command by resolving the provided
        /// command parameter against 
        /// </summary>
        /// <param name="executeCommandPara">The para.</param>
        public virtual void HandleCommandExecuteMethod(object executeCommandPara)
        {
            // Resolve the command provided by Command parameter. Commands are registered 
            // in the UserManagerModule. If command was not registered it will be logged and
            // return null.  Commands are stateless so they should use the ViewModel to maintain
            // state.  Be sure to unscribe to any event aggregator events!
            using (var command = Container.ResolveCommand(executeCommandPara.ToString()))
            {
                if (command == null) return;

                // Provide command a reference to this presenter so that
                // it will have everything it needs to process command
                // (Presenter has access to View and ViewModel)
                command.Presenter = this;

                //::: Execute the command (button click) ::::::://
                command.Execute(executeCommandPara.ToString());
            }
        }

        /// <summary>
        /// Handles the can execute method.
        /// </summary>
        /// <param name="para">The para.</param>
        /// <returns></returns>
        public virtual bool HandleCommandCanExecuteMethod(object para)
        {
            return true;
        }

        /// <summary>
        /// Initializeds this instance.
        /// </summary>
        public virtual void Initialized()
        {
        }

        /// <summary>
        /// Called by application controller when view is activated
        /// </summary>
        public virtual void ViewActivated()
        {
        }
    }
}
